package com.tbvtc.agriculturalcreditchainserver2025.service.impl;

import com.tbvtc.agriculturalcreditchainserver2025.async.AsyncQueryService;
import com.tbvtc.agriculturalcreditchainserver2025.dto.Pest.cropPestReportDto;
import com.tbvtc.agriculturalcreditchainserver2025.exception.FoodException;
import com.tbvtc.agriculturalcreditchainserver2025.properties.ContractAdressProperties;
import com.tbvtc.agriculturalcreditchainserver2025.service.PestService;
import com.tbvtc.agriculturalcreditchainserver2025.utils.BlockBaseUtils;
import com.tbvtc.agriculturalcreditchainserver2025.utils.BlockchainUtils;
import com.tbvtc.agriculturalcreditchainserver2025.utils.ResultCodeEnum;
import com.tbvtc.agriculturalcreditchainserver2025.utils.UserType;
import com.tbvtc.agriculturalcreditchainserver2025.constant.RedisConstant;
import com.tbvtc.agriculturalcreditchainserver2025.vo.Pest.getCropPestReportVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class PestServiceImpl implements PestService {

    @Autowired
    private BlockchainUtils blockchainUtils;
    @Autowired
    private BlockBaseUtils blockBaseUtils;
    @Autowired
    private ContractAdressProperties contractAdressProperties;
    @Autowired
    @Qualifier("TredisTemplate")
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private AsyncQueryService asyncQueryService;

    /**
     * 添加病虫害报告
     *
     * @param
     * @return
     * @throws IOException
     */
    @Override

    @CacheEvict(value = RedisConstant.CROP_PEST_PREFIX, key = "#cropPestReport.cropName")
    public void addPestReport(cropPestReportDto cropPestReport)  {

        List<Object> list = List.of(cropPestReport.getCropName()
                , cropPestReport.getPestName()
                , cropPestReport.getPestSeverity()
                , cropPestReport.getPestPhotos()
                , cropPestReport.getTreatmentMethod()
        );
        try {
            blockchainUtils.sendTransaction("FarmerManagement"
                    , "addCropPestReport"
                    , contractAdressProperties.getFarmerManagementAddress()
                    , list,
                    blockBaseUtils.getPemFilePath(UserType.FARMER));
        } catch (Exception e) {
            throw new FoodException(ResultCodeEnum.FAILED_TO_CHAIN);
        }
        String key = RedisConstant.CROP_PEST_PREFIX + cropPestReport.getCropName();

    }

    /**
     * 获取病虫害报告
     *
     * @param cropName
     * @return
     */
    @Override
//    @Cacheable(value = RedisConstant.CROP_PEST_PREFIX, key = "#cropName")
//    public List<getCropPestReportVo> getPestReport(String cropName) {
//        try {
//            List<Object> reportCount = blockchainUtils.callContract(
//                    "FarmerManagement"
//                    , "getPestReportCount"
//                    , contractAdressProperties.getFarmerManagementAddress()
//                    , List.of(cropName)
//                    , blockBaseUtils.getPemFilePath(UserType.FARMER));
//
//            BigInteger balance = (BigInteger) reportCount.get(0);
//
//            int count = balance.intValue();
//
//            List<CompletableFuture<getCropPestReportVo>> list = new ArrayList<>();
//            for (int i = 0; i < count; i++) {
//                list.add(asyncQueryService.getCropPestReport(cropName, i));
//            }
//            // 合并所有Future
//            CompletableFuture<Void> allFutures = CompletableFuture.allOf(
//                    list.toArray(new CompletableFuture[0])
//            );
//            // 等待所有任务完成
//            allFutures.join();
//            List<getCropPestReportVo> results = new ArrayList<>();
//            for (CompletableFuture<getCropPestReportVo> future : list) {
//                results.add(future.join());
//            }
////                redisTemplate.opsForValue().set(key, results);
//            return results;
//        } catch (Exception e) {
//            throw new leaseException(ResultCodeEnum.FAILED_TO_QUERY);
//        }
//
//
//    }
    public List<getCropPestReportVo> getPestReport(String cropName) {
        // 构建缓存Key
        String cacheKey = RedisConstant.CROP_PEST_PREFIX + cropName;

        try {
            // 1. 先从缓存获取
            List<getCropPestReportVo> cacheData = (List<getCropPestReportVo>) redisTemplate.opsForValue().get(cacheKey);
            if (cacheData != null) {
                return cacheData;
            }

            List<Object> reportCount = blockchainUtils.callContract(
                    "FarmerManagement",
                    "getPestReportCount",
                    contractAdressProperties.getFarmerManagementAddress(),
                    List.of(cropName),
                    blockBaseUtils.getPemFilePath(UserType.FARMER)
            );

            BigInteger balance = (BigInteger) reportCount.get(0);
            int count = balance.intValue();

            // 处理空结果防止缓存穿透
            if (count == 0) {
                List<getCropPestReportVo> emptyResult = Collections.emptyList();
                redisTemplate.opsForValue().set(cacheKey, emptyResult,
                        5 + new Random().nextInt(5), TimeUnit.MINUTES); // 短期缓存空结果
                return emptyResult;
            }

            // 3. 并行查询详情
            List<CompletableFuture<getCropPestReportVo>> futures = new ArrayList<>(count);
            for (int i = 0; i < count; i++) {
                futures.add(asyncQueryService.getCropPestReport(cropName, i));
            }

            // 合并结果
            CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                    futures.toArray(new CompletableFuture[0])
            );

            List<getCropPestReportVo> results = allFutures.thenApply(v ->
                    futures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList())
            ).join();

            // 4. 异步更新缓存（不阻塞主线程）
            CompletableFuture.runAsync(() -> {
                try {
                    // 设置随机过期时间防止雪崩 (1小时±10分钟)
                    int expireTime = 60 + new Random().nextInt(20);
                    redisTemplate.opsForValue().set(cacheKey, results, expireTime, TimeUnit.MINUTES);
                } catch (Exception e) {

                }
            });

            return results;
        } catch (Exception e) {
            e.printStackTrace();
            throw new FoodException(ResultCodeEnum.FAILED_TO_QUERY);
        }
    }
}
